<!--
<%
  @path = "#{rubber_env.graphite_dir}/webapp/content/dashboard.html"
%>

Simple graphite dashboard cycler for use on a large display - e.g. googletv/chrome on a wall mounted TV
 
-->

<html>
<head>
  <title>Graphite TV Dashboards</title>

  <style type="text/css">
    body {
      background-color: black;
    }

    .dashboard-title {
      color: yellow;
      text-align: center;
    }

    #paused_popup {
      display: none;
      background-color: gray;
      color: black;
      position: absolute;
      top: 0%;
      left: 0%;
      padding: 10px;
    }
  </style>

  <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.js"></script>

  <script type="text/javascript">

    //  To test this locally, edit ROOT_URL to point to graphite webapp (without trailing slash)
    //  To allow xhttp to graphite from html loaded from local file, run chrome with:
    // /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome  --disable-web-security
    
    var ROOT_URL = window.location.href.indexOf('file:') >= 0 ? "https://:8443" : "";

    function Dashboards(reloadAfterCycles, pageCount) {
      var self = this;

      self.reloadAfterCycles = reloadAfterCycles;
      self.pageCount = pageCount;
      self.cycleCount = 0;
      self.pages = [];
      self.pagesTmp = [];
      self.pageIdx = -1;

      self.reloadDashboards = function() {
        self.pages = [];
        self.pagesTmp = [];
        return $.when(self.dashboardList()).pipe(self.detailFromDashboardList).then(function() {
          console.log("Committing dashboard pages");

          self.pagesTmp.sort(function(x,y) {
            if (x.name() < y.name())
             return -1;
            if (x.name() > y.name())
             return 1;
            return 0;
          });
            
          $.each(self.pagesTmp, function(i, dashboard) {
             if (dashboard.graphCount() > self.pageCount)
             {
               var totalPages = Math.ceil(dashboard.graphCount() / self.pageCount);
               console.log("Splitting dashboard " + dashboard.name() + " into " + totalPages + " pages");
               
               for(i=0; i < totalPages; i++)
               {
                 var name = dashboard.name() + " " + (i+1) + "/" + totalPages;
                 self.pages.push(dashboard.subset(name, i * self.pageCount, self.pageCount));
                 console.log("Committed " + name +  " " + i * self.pageCount + " " + self.pageCount);  
               }
             }
             else
             {
               self.pages.push(dashboard);
             }
          });
            
        });
      }

      self.dashboardList = function() {
        console.log("Fetching all dashboards");

        return $.getJSON(ROOT_URL + '/dashboard/find/', {'query': ''});
      }

      self.detailFromDashboardList = function(data) {
        console.log("Got all dashboards");
        console.log(data);

        var chain = [];
        var dashboards = data["dashboards"];
        $.each(dashboards, function(i, dashboard) {
          var detailRequest = self.dashboardDetail(dashboard);
          chain.push(detailRequest);
        });
        return $.when.apply($, chain);
      }

      self.dashboardDetail = function(dashboard) {
        var name = dashboard["name"];
        console.log("Fetching dashboard detail for " + name);

        return $.getJSON(ROOT_URL + '/dashboard/load/' + name, {}, function(data) {

          console.log("Got dashboard detail for " + name);
          console.log(data);

          self.pagesTmp.push(new Dashboard(data));
        });
      }

      self.renderNextPage = function() {
        if (self.pages.length == 0)
        {
          console.log("No dashboard pages to render");
          return;
        }

        // always wrap around page idx when it gets too big
        self.pageIdx = (self.pageIdx + 1) % self.pages.length;

        console.log("Rendering next page " + self.pageIdx + "/" + self.pages.length);
        var result = self.pages[self.pageIdx].render();

        // reload dashboards on last page so its ready when we wrap around
        if (self.pageIdx == (self.pages.length - 1))
        {
          self.cycleCount++;
          if ((self.cycleCount % self.reloadAfterCycles) == 0)
          {
            self.reloadDashboards();
          }
        }

        return result;
      }

      self.renderPrevPage = function() {
        if (self.pages.length == 0)
        {
          console.log("No dashboard pages to render");
          return;
        }

        // always wrap around page idx when it gets too big
        self.pageIdx = self.pageIdx - 1
        if (self.pageIdx < 0) self.pageIdx = self.pages.length - 1;

        console.log("Rendering prev page " + self.pageIdx + "/" + self.pages.length);
        var result = self.pages[self.pageIdx].render();

        // reload dashboards on last page so its ready when we wrap around
        if (self.pageIdx == 0)
        {
          self.cycleCount++;
          if ((self.cycleCount % self.reloadAfterCycles) == 0)
          {
            self.reloadDashboards();
          }
          return;
        }

        return result;
      }
    }

    function Dashboard(apiData) {
      var self = this;
      
      self.apiData = apiData;

      self.name = function() {
        return self.apiData["state"]["name"];
      }
                
      self.graphCount = function() {
        return self.apiData["state"]["graphs"].length;
      }
                
      self.subset = function(newName, startIdx, howMany) {
        var newData = $.extend(true, {}, self.apiData);
        newData["state"]["name"] = newName;
        newData["state"]["graphs"] = newData["state"]["graphs"].splice(startIdx, howMany);
        var newDash = new Dashboard(newData);
        return newDash;
      }

      self.extractUrls = function() {
        var defaultParams = self.apiData["state"]["defaultGraphParams"];
        defaultParams = $.extend(true, {}, defaultParams); // deep copy

        defaultParams["width"] = "1050";
        defaultParams["height"] = "550";
        defaultParams["lineWidth"] = "3";
        
        if (! defaultParams["from"]) defaultParams["from"] = "-24hours";
        if (! defaultParams["until"]) defaultParams["until"] = "now";
        if (! defaultParams["title"]) defaultParams["title"] = "No Title";

        var urls = $.map(self.apiData["state"]["graphs"], function(e, i) {
          var defn = e[1];
          var params = $.extend(true, {}, defaultParams); // deep copy
          params = $.extend(true, params, defn); // deep copy

          // graphite only works with target=abc&target=xyz not with
          // standard form of target[]=abc&target[]=xyz
          var encoded_params = $.param(params).replace(/target%5B%5D=/g, "target=");
          var url = ROOT_URL + "/render?" + encoded_params;
          
          return url;
        });
        return urls;
      }

      self.render = function()
      {
        var name = self.apiData["state"]["name"];
        var dbdiv = $('<div class="dashboard"/>');

        var title = $('<div class="dashboard-title"/>')
        dbdiv.append(title);
        title.append(name);

        var images = $('<div class="dashboard-images"/>');
        dbdiv.append(images);

        var urls = self.extractUrls();
        $.each(urls, function(i, url) {
          var img = $("<img/>", {'src': url});
          images.append(img);
        });

        return dbdiv;
      }

    }

    function View(dashboards, pageDelay, pauseDelay) {
      var self = this;

      self.pageDelay = pageDelay;
      self.pauseDelay = pauseDelay;

      self.eventLoopDelay = 1000;
      self.eventLoopCount = 0;
      self.paused = false;

      self.dashboards = dashboards;

      self.eventLoop = function()
      {
        if (self.paused)
        {
          console.log("paused");
        }
        else if(self.dashboards.pages.length == 0)
        {
          console.log("Waiting for dashboards");
          self.eventLoopCount = 0;
        }
        else
        {
          var offset = (self.eventLoopCount * self.eventLoopDelay) % self.pageDelay;
          if (offset == 0)
          {
            console.log("Rendering next page")
            self.renderPage('next');
          }
          self.eventLoopCount++;
        }

        setTimeout(self.eventLoop, self.eventLoopDelay);
      }

      self.registerKeyBindings = function() {
        $(document).keydown(function(e){
          if (e.keyCode == 32) {
            self.togglePause();
            return false;
          }
          if (e.keyCode == 37) {
            console.log( "left pressed" );
            self.renderPage('prev');
            return false;
          }
          if (e.keyCode == 39) {
            console.log( "right pressed" );
            self.renderPage('next');
            return false;
          }
        });
      }

      self.togglePause = function() {
        self.paused ? self.unPause() : self.pause();
        if (self.paused) setTimeout(self.unPause, self.pauseDelay);
      }

      self.pause = function() {
        self.paused = true;
        $('#paused_popup').show();
        console.log("paused: " + self.paused);
      }

      self.unPause = function() {
        self.paused = false;
        $('#paused_popup').hide();
        console.log("paused: " + self.paused);
      }

      self.renderPage = function(direction)
      {
        var dbdiv = null;
        if (direction == 'next')
        {
          dbdiv = self.dashboards.renderNextPage();
        }
        else if (direction = 'prev')
        {
          dbdiv = self.dashboards.renderPrevPage();
        }
        else
        {
          console.log("Bad direction: " + direction);
          return;
        }

        if (dbdiv)
        {
          $('#main').fadeOut('slow', function() {
            $(".dashboard").remove();
            $("#main").append(dbdiv);
            $("#main").fadeIn('slow');
          });
        }
      }

    }


    function urlParams()
    {
      var vars = [], hash;
      var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
      for(var i = 0; i < hashes.length; i++)
      {
        hash = hashes[i].split('=');
        vars.push(hash[0]);
        vars[hash[0]] = hash[1];
      }
      return vars;
    }

    $(document).ready(function () {
      var reloadAfterCycles = urlParams()["reloadAfterCycles"] ? parseInt(urlParams()["reloadAfterCycles"]) : 5;
      var pageCount = urlParams()["pageCount"] ? parseInt(urlParams()["pageCount"]) : 4;
      var pageDelay = urlParams()["pageDelay"] ? parseInt(urlParams()["pageDelay"]) : 30000;
      var pauseDelay = urlParams()["pauseDelay"] ? parseInt(urlParams()["pauseDelay"]) : 30000;

      var dashboards = new Dashboards(reloadAfterCycles, pageCount);
      dashboards.reloadDashboards();

      var view = new View(dashboards, pageDelay, pauseDelay);
      view.registerKeyBindings();
      view.eventLoop();
    });


  </script>
</head>

<div id="main">
    <div id="paused_popup">Paused</div>
</div>

</html>
